package com.pandora.loan.home.service.impl;

import com.pandora.loan.common.util.Constants;
import com.pandora.loan.common.util.JedisUtil;
import com.pandora.loan.common.util.SignatureMaker;
import com.pandora.loan.common.util.StringUtils;
import com.pandora.loan.home.dao.AccountDao;
import com.pandora.loan.home.dto.request.AccessTokenRequest;
import com.pandora.loan.home.dto.response.AccessTokenResponse;
import com.pandora.loan.home.entity.Account;
import com.pandora.loan.home.exception.EmptyRequestException;
import com.pandora.loan.home.exception.token.*;
import com.pandora.loan.home.service.AccountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author developer
 */
@Service
public class AccountServiceImpl implements AccountService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AccountDao accountDao;

    @Override
    public Account getById(long id) {
        return accountDao.queryById(id);
    }

    @Override
    @Cacheable(value = "account")
    public List<Account> getByStatus(int status) {
        return accountDao.queryByStatus(status);
    }

    private void validateAccessTockenRequest(AccessTokenRequest req) {
        if (req == null) {
            throw new EmptyRequestException();
        }
        logger.info("check signature app_id:{} ts:{} sign:{} for fetching access_token!", req.getAppId(), req.getTimeStamp(), req.getSign());
        String appId = req.getAppId();
        if (StringUtils.isEmpty(appId)) {
            throw new EmptyAppIdException();
        }
        String timestamp = req.getTimeStamp();
        if (StringUtils.isEmpty(timestamp)) {
            throw new EmptyTimestampException();
        }
        String sign = req.getSign();
        if (StringUtils.isEmpty(sign)) {
            throw new EmptySignException();
        }
        if (!StringUtils.isStrToLong(appId)) {
            throw new InvalidAppIdException();
        }
        if (!StringUtils.isStrToLong(timestamp)) {
            throw new InvalidTimestampException();
        }
        long gap = Math.abs(System.currentTimeMillis() * 1000 - Long.parseLong(timestamp));
        if (gap > Constants.ACCESS_TOKEN_TS_GAP) {
            throw new InvalidTimestampException();
        }
        Account account = getById(Long.parseLong(appId));
        if (account == null) {
            logger.error("No account record in DB app_id:{} for fetching access_token!", appId);
            // 此处不应是该异常
            throw new InvalidTimestampException();
        }
        if (StringUtils.isEmpty(account.getSecret())) {
            logger.error("No account secret in DB app_id:{} for fetching access_token!", appId);
            throw new EmptyAppSecretException();
        }
        if (StringUtils.isEmpty(account.getPubKey())) {
            logger.error("No account pub_key in DB app_id:{} for fetching access_token!", appId);
            throw new EmptyPubKeyException();
        }
        String params = SignatureMaker.getSignContent(appId, account.getSecret(), timestamp);
        boolean bool = SignatureMaker.verify(params, sign, Constants.PUBLIC_KEY);
        if (!bool) {
            logger.error("Bad signature app_id:{} ts:{} sign:{} for fetching access_token!", appId, timestamp, sign);
            throw new InvalidSignException();
        }
    }

    @Override
    public AccessTokenResponse requestAccessToken(AccessTokenRequest req) {
        validateAccessTockenRequest(req);
        String appId = req.getAppId();
        String accessToken = JedisUtil.get(Constants.BUSINESS_REDIS_URL,
                StringUtils.getStrParam(Constants.APP_ACCESS_TOKEN_KEY, appId));
        if (StringUtils.isEmpty(accessToken)) {
            long nowTime = System.currentTimeMillis();
            accessToken = StringUtils.encoderByMd5(String.valueOf(nowTime));
            JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.APP_ACCESS_TOKEN_KEY, appId),
                    accessToken,
                    Constants.ACCESS_TOKEN_EXPIRATION);
            JedisUtil.set(Constants.BUSINESS_REDIS_URL,
                    StringUtils.getStrParam(Constants.ACCESS_TOKEN_KEY, accessToken),
                    appId,
                    Constants.ACCESS_TOKEN_EXPIRATION);
        }
        return new AccessTokenResponse(accessToken);
    }

}
